package cn.fastoo.common.sampleframe.search;

import cn.fastoo.common.sampleframe.springside.SearchFilter;
import cn.fastoo.common.sampleframe.springside.SearchFilter;
import cn.fastoo.common.sampleframe.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import java.util.*;
import java.util.Map.Entry;


public class Search {
	
	private Map<String, SearchFilter> core = new HashMap<String, SearchFilter>();
	
	private PageRequest pageRequest;
	
	private Sort sort;
	
	private List<Search> orCore = new ArrayList<Search>();
	
	private List<String> select = new ArrayList<String>();

	private Integer limit = null;

	private Boolean forUpdate = false;
	
	public Search or(Search search){
		if(search==null){
			return null;
		}
		if(search.values().isEmpty()){
			return this;
		}
		getOrCore().add(search);
		return this; 
	}
	
	
	public Search addSearchFilter(String fieldName,SearchFilter.Operator operator,Object value){
		core.put(fieldName, new SearchFilter(fieldName, operator, value));
		return this;
	}
	 
	public Search removeSearchFilter(String fieldName){
		core.remove(fieldName);
		return this;
	}
	
	public SearchFilter getSearchFilter(String fieldName){
		if(!core.containsKey(fieldName)){
			return null; 
		}
		return core.get(fieldName);
	}
	
	private SearchFilter getSearchFilter(String key,Object value){
		 
		// 拆分operator与filedAttribute
		String[] names = StringUtils.split(key, "_");
		if (names.length != 2) {
			throw new IllegalArgumentException(key + " is not a valid search filter name");
		}
		String filedName = names[1];
		String operatorStr = names[0];
		if(operatorStr.contains("date")){
			operatorStr = operatorStr.substring(0,operatorStr.lastIndexOf("date"));
			value = DateUtils.convertToDate(value.toString());
		} 
		SearchFilter.Operator operator = SearchFilter.Operator.valueOf(operatorStr);
		if(operator.equals(SearchFilter.Operator.IN) || SearchFilter.Operator.NOTIN.equals(operator)){
			if(value instanceof String){
				value = value.toString().split(",");
			}
		}
		return new SearchFilter(filedName,  SearchFilter.Operator.valueOf(operatorStr), value);
	}
	
	public Search addSearchFilter(String key,Object value){

			if (value instanceof String) {
				if (StringUtils.isBlank((String) value)) {
						return this;
				}
			}
			 
			// 拆分operator与filedAttribute
			String[] names = StringUtils.split(key, "_");
			if (names.length != 2) {
				throw new IllegalArgumentException(key + " is not a valid search filter name");
			} 
			// 创建searchFilter
			SearchFilter filter = getSearchFilter(key, value);
			if(core.containsKey(filter.fieldName)){
				core.put(filter.fieldName+"_"+System.currentTimeMillis(), filter);
			}else{
				core.put(filter.fieldName, filter);
			}
			
			return this;
	}
	
	public Search addSearchFilter(Map<String, Object> searchParams){
			for (Entry<String, Object> entry : searchParams.entrySet()) {
				 addSearchFilter(entry.getKey(),entry.getValue());
			}
			return this;
	}
	
	public Collection<SearchFilter> values(){
		return core.values();
	}
	


	public PageRequest getPageRequest() {
		return pageRequest;
	}

	public Search addPageRequest(PageRequest pageRequest) {
		this.pageRequest = pageRequest;
		return this;
	}


	public Sort getSort() {
		return sort;
	}


	public Search addSort(Sort sort) {
		this.sort = sort;
		return this;
	}


	public List<Search> getOrCore() {
		return orCore;
	}


	public List<String> getSelect() {
		return select;
	}


	public Search select(String sql) {
		this.select.add(sql);
		return this; 
	} 
	public Search jpaSelect(String sql){
		this.select.add(String.format("jpa:%s", sql));
		return this; 
	}
	
	public  String getStringSearchVal(String fieldName ){
		SearchFilter obj = getSearchFilter(fieldName);
		if(obj==null){
			return null;
		}
		return obj.value.toString();
	}


	public Integer getLimit() {
		return limit;
	}

	public Search addLimit(Integer litmit) {
		this.limit = litmit;
		return this;
	}
	public Search forUpdate(){
		forUpdate = true;
		return this;
	}


	public Boolean getForUpdate() {
		return forUpdate;
	}

}
